﻿//Copyright 2011 Kael Russell
//This file is part of il2dynamiccampaign.
//
//il2dynamiccampaign is free software: you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//
//il2dynamiccampaign is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with il2dynamiccampaign.  If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using maddox.game;
using maddox.game.world;

//using System.Diagnostics;
using System.Text;
using System.Windows.Forms;

namespace TEF.dynCampaign
{
    public partial class DynamicMission : AMission
    {
        #region variables

        private const string USER_FOLDER = "$user/mission/TEFCampaign/";
        private const string CAMPAIGN_FOLDER = "$home/parts/TEFCampaign/campaign/";
        private string USER_PATH;
        private string PATH;
        private string PLAYER_FLIGHT = "BoB_LW_JG51_I.01";
        private int PLAYER_AIRBASE_X = 276025;
        private int PLAYER_AIRBASE_Y = 207448;

        private int XMINBOUND;
        private int XMAXBOUND;
        private int YMINBOUND;
        private int YMAXBOUND;

        private List<string> RED_COASTAL_SECTORS = new List<string>();
        private List<int> usedTacNums = new List<int>();
        
        private int currentFlightNum = 2;
        private int maxAiSkill = 7;
        private int minAiSkill = 3;
        private int maxAircraft = 20;
        private int minAircraft = 10;

        private ISectionFile playerState;
        private ISectionFile campaignInfo;
        private ISectionFile redAircraft;
        private ISectionFile blueAircraft;
        private PlayerInfo player;

        private bool playerDead = false;
        private bool firstMission = false;

        #endregion

        #region IL-2

        public ICampaign Campaign
        {
            get { return (GamePlay as ICampaign); }
        }
        public override void OnSingleBattleSuccess(bool success)
        {
            OnSingleBattleSuccess(success, false);
        }
        public void OnSingleBattleSuccess(bool success, bool fromMe)
        {
            if (fromMe)
            {
                if ((Campaign != null))
                    Campaign.battleSuccess = success;
            }
        }

        public override void OnActorDead(int missionNumber, string shortName, AiActor actor, List<DamagerScore> damages)
        {
            base.OnActorDead(missionNumber, shortName, actor, damages);

            if (!GamePlay.gpPlayer().Place().IsAlive())
                playerDead = true;
            
            if (actor != null && damages.Count > 0)
            {
                foreach (DamagerScore d in damages)
                {
                    if (d.score > .5 && d.initiator.Player != null)
                        player.addVictory((actor as AiAircraft));
                }
            }
        }

        public override void OnBattleStarted()
        {
            base.OnBattleStarted();
            
            setup();
        }

        public override void OnBattleStoped()
        {
            base.OnBattleStoped();
            
            //if playerString is still alive, battle is a success, create next mission
            if (playerDead && Campaign != null)
                OnSingleBattleSuccess(false, true);
            else if (Campaign != null)
            {
                OnSingleBattleSuccess(true, true);
                
                if(!firstMission)
                    player.addDays(1);

                player.save(playerState, USER_PATH + "playerState.ini");

                if (player.getDate().CompareTo(DateTime.Parse(campaignInfo.get("Info", "endDate"))) > 0)
                    endCampaign();
                else
                    createNextMission();
            }
        }

        #endregion

        #region flightCreation

        /// <summary>
        /// Creates a properly formatted string for the skill of an airgroup. The range is constrained by maxAiSkill and minAiSkill.
        /// </summary>
        /// <returns>A string representing an airgroups skill.</returns>
        private string randomSkill()
        {
            string skill = "";
            Random rand = new Random();

            for (int i = 0; i < 8; i++)
            {
                string temp = "0." + rand.Next(minAiSkill, maxAiSkill + 1);
                skill += temp + " ";
            }
            return skill;
        }

        /// <summary>
        /// Creates a string that will be appropriate to add to an airgroup's "Flight" key. Aircraft will receive random tactical numbers
        /// between one and ninety-nine.
        /// </summary>
        /// <param name="numAircraft">The number of aircraft in the flight.</param>
        /// <returns>A string representing an airgroups "Flight" key.</returns>
        private string flightValueString(int numAircraft)
        {
            Random rand = new Random();
            string value = "";

            if (usedTacNums.Count > 80)
                usedTacNums.Clear();

            for (int i = 1; i <= numAircraft; i++)
            {
                int tacNum = rand.Next(1, 100);

                while (usedTacNums.Contains(tacNum))
                    tacNum = rand.Next(1, 100);

                value += tacNum + " ";
                usedTacNums.Add(tacNum);
            }

            value.Trim();
            return value;
        }

        /// <summary>
        /// Chooses a random flight of aircraft of the specified type from the specified file. The file must be formatted properly.
        /// </summary>
        /// <param name="redAircraft">The file to choose the aircraft from.</param>
        /// <param name="type">The type of aircraft to choose.</param>
        /// <returns>An un-numbered airgroup string.</returns>
        private string chooseRandomFlight(ISectionFile aircraftFile, string type)
        {
            string flight = "";
            string Class;
            int count = 0;

            bool fighters = false;

            if (!aircraftFile.exist(type))
                return flight;

            Random rand = new Random();

            if (type == "Fighters")
                fighters = true;

            do
            {
                if (fighters)
                    if (rand.Next(2) == 1)
                        type = "Fighters";
                    else
                        type = "Jabo";

                int line = rand.Next(0, aircraftFile.lines(type));
                string value;

                aircraftFile.get(type, line, out flight, out value);

                if (type == "Jabo" && !fighters)
                    Class = aircraftFile.get(flight, "JaboClass");
                else
                    Class = aircraftFile.get(flight, "Class");

                count++;

                if (count >= 12500)
                {
                    MessageBox.Show("ERROR: Infinite loop detected!\nThis is usually caused by excluding all aircraft of a certain class (e.g. bombers, jabos, etc.).");
                    break;
                }
            } 
            while (Class == null || !campaignInfo.get("Aircraft", "Included").Contains(Class));

            return flight;
        }

        private string createJaboFlight(ISectionFile file, int army, int aircraft, MissionInfo mission, bool playerEscort)
        {
            int airBaseX = 0;
            int airBaseY = 0;

            Random rand = new Random();

            if (aircraft <= 0)
                aircraft = rand.Next(1, 9);

            ISectionFile aircraftFile;
            if (army == 1)
                aircraftFile = redAircraft;
            else
                aircraftFile = blueAircraft;

            string airGroup = chooseRandomFlight(aircraftFile, "Jabo");
            string flight = airGroup + "." + currentFlightNum.ToString("00");
            currentFlightNum += 1;

            file.add("AirGroups", flight, "");

            for (int i = 0; i < aircraftFile.lines(airGroup); i++)
            {
                string key, value;
                aircraftFile.get(airGroup, i, out key, out value);

                switch (key)
                {
                    case "Weapons":
                        value = aircraftFile.get(airGroup, "JaboWeapons");
                        break;
                    case "Class":
                        value = aircraftFile.get(airGroup, "JaboClass");
                        break;
                    case "Skill":
                        value = randomSkill();
                        break;
                    case "Airbase":
                        if (value.Equals("Random"))
                            getRandomAirbase(army, out airBaseX, out airBaseY);

                        else
                        {
                            string[] coords = value.Split(' ');
                            airBaseX = Int32.Parse(coords[0]);
                            airBaseY = Int32.Parse(coords[1]);
                        }
                        continue;
                }

                file.add(flight, key, value);
            }

            //fighters flights are in sets of 4.
            //if less than four, just add them to flight0 and continue
            if (aircraft <= 4)
                file.set(flight, "Flight0", flightValueString(aircraft));
            else
            {
                //if there are more than four, add the first four to flight0
                int flightNum = 0;
                file.set(flight, "Flight" + flightNum, flightValueString(4));
                aircraft -= 4;
                flightNum++;

                //if there are still more than four, add flights of four until there are less than four remaining
                for (int i = 0; i < aircraft / 4; i++)
                {
                    file.set(flight, "Flight" + flightNum, flightValueString(4));
                    aircraft -= 6;
                    flightNum++;
                }

                //if there are still one or two fighters to be added, add them to the next flight
                if (aircraft > 0)
                    file.set(flight, "Flight" + flightNum, flightValueString(aircraft));
            }

            setAirspawnWaypoint(file, flight, airBaseX, airBaseY);

            mission.altitude = 1000;

            if (playerEscort)
            {
                setSmallAiPatrol(file, flight, PLAYER_AIRBASE_X, PLAYER_AIRBASE_Y, mission.altitude, 1);
                setJaboWaypoint(file, flight, army, mission, "Aircraft");
            }
            else
            {
                setSmallAiPatrol(file, flight, airBaseX, airBaseY, mission.altitude, 1);
                setJaboWaypoint(file, flight, army, mission);
            }

            setLandingWaypoint(file, flight, airBaseX, airBaseY, mission.altitude);

            ageFlight(file, flight, rand.Next(1, 76));

            mission.targetType = aircraftFile.get(airGroup, "JaboClass").Split('.')[1];
            mission.sector = GamePlay.gpSectorName(mission.xPos, mission.yPos);

            return flight;
        }

        private string createJaboFlight(ISectionFile file, int army, int aircraft)
        {
            return createJaboFlight(file, army, aircraft, new MissionInfo(), false);
        }

        /// <summary>
        /// Creates a random flight of fighters to escort a flight of bombers.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="army">The army of the airgroup to be escorted.</param>
        /// <param name="target">The airgroup the fighters are to escort.</param>
        /// <param name="numFighters">The number of fighters that will escort the bombers.</param>
        private void createBomberEscort(ISectionFile file, int army, string target, int numFighters)
        {
            if (army == 1)
                createRedBomberEscort(file, target, numFighters);
            else
                createBlueBomberEscort(file, target, numFighters);
        }

        /// <summary>
        /// Creates a random flight of red fighters to escort a flight of bombers.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="target">The airgroup the fighters are to escort.</param>
        /// <param name="numFighters">The number of fighters that will escort the bombers.</param>
        private void createRedBomberEscort(ISectionFile file, string target, int numFighters)
        {
            int airBaseX = 0;
            int airBaseY = 0;

            Random rand = new Random();

            if (numFighters <= 0)
                numFighters = rand.Next(1, 7);

            string airGroup = chooseRandomFlight(redAircraft, "Fighters");
            string flight = airGroup + "." + currentFlightNum.ToString("00");
            currentFlightNum += 1;

            file.add("AirGroups", flight, "");

            for (int i = 0; i < redAircraft.lines(airGroup); i++)
            {
                string key, value;
                redAircraft.get(airGroup, i, out key, out value);

                switch (key)
                {
                    case "Skill":
                        value = randomSkill();
                        break;
                    case "Airbase":
                        if (value.Equals("Random"))
                            getRandomAirbase(1, out airBaseX, out airBaseY);

                        else
                        {
                            string[] coords = value.Split(' ');
                            airBaseX = Int32.Parse(coords[0]);
                            airBaseY = Int32.Parse(coords[1]);
                        }
                        continue;
                }

                file.add(flight, key, value);
            }

            //fighters flights are in sets of 6.
            //if less than six, just add them to flight0 and continue
            if (numFighters <= 6)
                file.set(flight, "Flight0", flightValueString(numFighters));
            else
            {
                //if there are more than six, add the first six to flight0
                int flightNum = 0;
                file.set(flight, "Flight" + flightNum, flightValueString(6));
                numFighters -= 6;
                flightNum++;

                //if there are still more than six, add flights of six until there are less than six remaining
                for (int i = 0; i < numFighters / 6; i++)
                {
                    file.set(flight, "Flight" + flightNum, flightValueString(6));
                    numFighters -= 6;
                    flightNum++;
                }

                //if there are still one or two fighters to be added, add them to the next flight
                if (numFighters > 0)
                    file.set(flight, "Flight" + flightNum, flightValueString(numFighters));
            }

            string bomberWay, bomberValue;
            file.get(target + "_Way", 2, out bomberWay, out bomberValue);
            string[] bomberValues = bomberValue.Split(' ');
            

            setAirspawnWaypoint(file, flight, Int32.Parse(bomberValues[0]) - 2000, Int32.Parse(bomberValues[1]), 1000);

            int newAltitude = Int32.Parse(bomberValues[2]) + rand.Next(200, 700);
            setEscortWaypoint(file, Int32.Parse(bomberValues[0]), Int32.Parse(bomberValues[1]), flight, target, newAltitude);

            setLandingWaypoint(file, flight, airBaseX, airBaseY, newAltitude);

            ageFlight(file, flight, rand.Next(1, 76));
        }

        /// <summary>
        /// Creates a random flight of blue fighters to escort a flight of bombers.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="target">The airgroup the fighters are to escort.</param>
        /// <param name="numFighters">The number of fighters that will escort the bombers.</param>
        private void createBlueBomberEscort(ISectionFile file, string target, int numFighters)
        {
            int airBaseX = 0;
            int airBaseY = 0;

            Random rand = new Random();

            if (numFighters <= 0)
                numFighters = rand.Next(1, 9);

            string airGroup = chooseRandomFlight(blueAircraft, "Fighters");
            string flight = airGroup + "." + currentFlightNum.ToString("00");
            currentFlightNum += 1;

            file.add("AirGroups", flight, "");

            for (int i = 0; i < blueAircraft.lines(airGroup); i++)
            {
                string key, value;
                blueAircraft.get(airGroup, i, out key, out value);

                switch (key)
                {
                    case "Skill":
                        value = randomSkill();
                        break;
                    case "Airbase":
                        if (value.Equals("Random"))
                            getRandomAirbase(2, out airBaseX, out airBaseY);

                        else
                        {
                            string[] coords = value.Split(' ');
                            airBaseX = Int32.Parse(coords[0]);
                            airBaseY = Int32.Parse(coords[1]);
                        }
                        continue;
                }

                file.add(flight, key, value);
            }

            //fighters flights are in sets of 4.
            //if less than four, just add them to flight0 and continue
            if (numFighters <= 4)
                file.set(flight, "Flight0", flightValueString(numFighters));
            else
            {
                //if there are more than four, add the first four to flight0
                int flightNum = 0;
                file.set(flight, "Flight" + flightNum, flightValueString(4));
                numFighters -= 4;
                flightNum++;

                //if there are still more than four, add flights of four until there are less than four remaining
                for (int i = 0; i < numFighters / 4; i++)
                {
                    file.set(flight, "Flight" + flightNum, flightValueString(4));
                    numFighters -= 4;
                    flightNum++;
                }

                //if there are still one or two fighters to be added, add them to the next flight
                if (numFighters > 0)
                    file.set(flight, "Flight" + flightNum, flightValueString(numFighters));
            }

            string bomberWay, bomberValue;
            file.get(target + "_Way", 2, out bomberWay, out bomberValue);
            string[] bomberValues = bomberValue.Split(' ');


            setAirspawnWaypoint(file, flight, Int32.Parse(bomberValues[0]) - 2000, Int32.Parse(bomberValues[1]), 1000);

            int newAltitude = Int32.Parse(bomberValues[2]) + rand.Next(200, 700);
            setEscortWaypoint(file, Int32.Parse(bomberValues[0]), Int32.Parse(bomberValues[1]), flight, target, newAltitude);

            setLandingWaypoint(file, flight, airBaseX, airBaseY, newAltitude);

            ageFlight(file, flight, rand.Next(1, 76));
        }

        /// <summary>
        /// Creates a flight of fighters that will patrol around xPos and yPos.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="army">The army the fighters will belong to.</param>
        /// <param name="numFighters">The number of fighters. Must be greater than zero, less than 7 for red, less than 9 for blue.</param>
        /// <param name="xPos">The X coordinate where the fighters will patrol.</param>
        /// <param name="yPos">The Y coordinate where the fighters will patrol.</param>
        /// <param name="altitude">The altitude the fighters will patrol at.</param>
        private void createAiInterceptFlight(ISectionFile file, int army, int numFighters, int xPos, int yPos, int altitude)
        {
            int airBaseX = 0;
            int airBaseY = 0;

            Random rand = new Random();

            if (army == 1)
            {
                if (numFighters > 6 || numFighters <= 0)
                    numFighters = rand.Next(1, 7);
            }
            else
            {
                if (numFighters > 8 || numFighters <= 0)
                    numFighters = rand.Next(1, 9);
            }

            ISectionFile aircraftFile;
            if (army == 1)
                aircraftFile = redAircraft;
            else
                aircraftFile = blueAircraft;

            string airGroup = chooseRandomFlight(aircraftFile, "Fighters");
            string flight = airGroup + "." + currentFlightNum.ToString("00");
            currentFlightNum += 1;

            file.add("AirGroups", flight, "");

            for (int i = 0; i < aircraftFile.lines(airGroup); i++)
            {
                string key, value;
                aircraftFile.get(airGroup, i, out key, out value);

                switch (key)
                {
                    case "Flight0":
                        value = flightValueString(numFighters);
                        break;
                    case "Skill":
                        value = randomSkill();
                        break;
                    case "Airbase":
                        if (value.Equals("Random"))
                            getRandomAirbase(army, out airBaseX, out airBaseY);

                        else
                        {
                            string[] coords = value.Split(' ');
                            airBaseX = Int32.Parse(coords[0]);
                            airBaseY = Int32.Parse(coords[1]);
                        }
                        continue;
                }

                file.add(flight, key, value);
            }

            setTakeoffWaypoint(file, flight, airBaseX, airBaseY);

            int newAltitude = altitude + rand.Next(-700, 700);
            setAiPatrol(file, flight, xPos, yPos, newAltitude, rand.Next(5, 11));

            setLandingWaypoint(file, flight, airBaseX, airBaseY, newAltitude);

            ageFlight(file, flight, rand.Next(1, 76));
        }

        /// <summary>
        /// Creates a random red fighter group that will patrol around a random point from the "RED_COASTAL_SECTORS" list.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="numFighters">The number of fighters.</param>
        private void createRandomRedFighterPatrol(ISectionFile file, int numFighters)
        {
            int airBaseX = 0;
            int airBaseY = 0;

            Random rand = new Random();

            if (numFighters <= 0)
                numFighters = rand.Next(1, 7);

            string airGroup = chooseRandomFlight(redAircraft, "Fighters");
            string flight = airGroup + "." + currentFlightNum.ToString("00");
            currentFlightNum += 1;

            file.add("AirGroups", flight, "");

            for (int i = 0; i < redAircraft.lines(airGroup); i++)
            {
                string key, value;
                redAircraft.get(airGroup, i, out key, out value);

                switch (key)
                {
                    case "Skill":
                        value = randomSkill();
                        break;
                    case "Airbase":
                        if (value.Equals("Random"))
                            getRandomAirbase(1, out airBaseX, out airBaseY);

                        else
                        {
                            string[] coords = value.Split(' ');
                            airBaseX = Int32.Parse(coords[0]);
                            airBaseY = Int32.Parse(coords[1]);
                        }
                        continue;
                }

                file.add(flight, key, value);
            }

            //fighters flights are in sets of 6.
            //if less than six, just add them to flight0 and continue
            if (numFighters <= 6)
                file.set(flight, "Flight0", flightValueString(numFighters));
            else
            {
                //if there are more than six, add the first six to flight0
                int flightNum = 0;
                file.set(flight, "Flight" + flightNum, flightValueString(6));
                numFighters -= 6;
                flightNum++;

                //if there are still more than six, add flights of six until there are less than six remaining
                for (int i = 0; i < numFighters / 6; i++)
                {
                    file.set(flight, "Flight" + flightNum, flightValueString(6));
                    numFighters -= 6;
                    flightNum++;
                }

                //if there are still one or two fighters to be added, add them to the next flight
                if (numFighters > 0)
                    file.set(flight, "Flight" + flightNum, flightValueString(numFighters));
            }

            setTakeoffWaypoint(file, flight, airBaseX, airBaseY);

            int altitude = rand.Next(1000, 5000);

            int xPos = 0;
            int yPos = 0;
            string sector = "";

            while (!RED_COASTAL_SECTORS.Contains(sector))
            {
                xPos = rand.Next(XMINBOUND, XMAXBOUND);
                yPos = rand.Next(YMINBOUND, YMAXBOUND);
                sector = GamePlay.gpSectorName(xPos, yPos);
            }

            setAiPatrol(file, flight, xPos, yPos, altitude, rand.Next(5, 11));

            setLandingWaypoint(file, flight, airBaseX, airBaseY, altitude);

            ageFlight(file, flight, rand.Next(1, 76));
        }

        /// <summary>
        /// Creates a random blue fighter group that will patrol around a random point from the "RED_COASTAL_SECTORS" list.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="numFighters">The number of fighters.</param>
        private void createRandomBlueFighterPatrol(ISectionFile file, int numFighters)
        {
            int airBaseX = 0;
            int airBaseY = 0;

            Random rand = new Random();

            if (numFighters <= 0)
                numFighters = rand.Next(1, 7);

            string airGroup = chooseRandomFlight(blueAircraft, "Fighters");
            string flight = airGroup + "." + currentFlightNum.ToString("00");
            currentFlightNum += 1;

            file.add("AirGroups", flight, "");

            for (int i = 0; i < blueAircraft.lines(airGroup); i++)
            {
                string key, value;
                blueAircraft.get(airGroup, i, out key, out value);

                switch (key)
                {
                    case "Skill":
                        value = randomSkill();
                        break;
                    case "Airbase":
                        if (value.Equals("Random"))
                            getRandomAirbase(2, out airBaseX, out airBaseY);

                        else
                        {
                            string[] coords = value.Split(' ');
                            airBaseX = Int32.Parse(coords[0]);
                            airBaseY = Int32.Parse(coords[1]);
                        }
                        continue;
                }

                file.add(flight, key, value);
            }

            //fighters flights are in sets of 4.
            //if less than three, just add them to flight0 and continue
            if (numFighters <= 4)
                file.set(flight, "Flight0", flightValueString(numFighters));
            else
            {
                //if there are more than four, add the first four to flight0
                int flightNum = 0;
                file.set(flight, "Flight" + flightNum, flightValueString(4));
                numFighters -= 4;
                flightNum++;

                //if there are still more than four, add flights of four until there are less than four remaining
                for (int i = 0; i < numFighters / 4; i++)
                {
                    file.set(flight, "Flight" + flightNum, flightValueString(4));
                    numFighters -= 4;
                    flightNum++;
                }

                //if there are still one or two fighters to be added, add them to the next flight
                if (numFighters > 0)
                    file.set(flight, "Flight" + flightNum, flightValueString(numFighters));
            }

            setTakeoffWaypoint(file, flight, airBaseX, airBaseY);

            int altitude = rand.Next(1000, 5000);

            int xPos = 0;
            int yPos = 0;
            string sector = "";

            while (!RED_COASTAL_SECTORS.Contains(sector))
            {
                xPos = rand.Next(XMINBOUND, XMAXBOUND);
                yPos = rand.Next(YMINBOUND, YMAXBOUND);
                sector = GamePlay.gpSectorName(xPos, yPos);
            }

            setAiPatrol(file, flight, xPos, yPos, altitude, rand.Next(4, 9));

            setLandingWaypoint(file, flight, airBaseX, airBaseY, altitude);

            ageFlight(file, flight, rand.Next(1, 76));
        }

        /// <summary>
        /// Creates a random flight of level bombers that will bomb a random point of land on the opposing army's side of the front.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="army">The army that the bombers will fly for.</param>
        /// <param name="numBombers">The number of bombers.</param>
        /// <returns></returns>
        private string createRandomBomberFlight(ISectionFile file, int army, int numBombers)
        {
            int airBaseX = 0;
            int airBaseY = 0;
            int enemy;

            Random rand = new Random();

            if (numBombers > 10 || numBombers <= 0)
                numBombers = rand.Next(1, 11);

            ISectionFile aircraftFile;

            if (army == 1)
            {
                aircraftFile = redAircraft;
                enemy = 2;
            }
            else
            {
                aircraftFile = blueAircraft;
                enemy = 1;
            }

            string airGroup = chooseRandomFlight(aircraftFile, "Bombers");
            string flight = airGroup + "." + currentFlightNum.ToString("00");
            currentFlightNum += 1;

            file.add("AirGroups", flight, "");

            for (int i = 0; i < aircraftFile.lines(airGroup); i++)
            {
                string key, value;
                aircraftFile.get(airGroup, i, out key, out value);

                switch (key)
                {
                    case "Skill":
                        value = randomSkill();
                        break;
                    case "Airbase":
                        if (value.Equals("Random"))
                            getRandomAirbase(army, out airBaseX, out airBaseY);

                        else
                        {
                            string[] coords = value.Split(' ');
                            airBaseX = Int32.Parse(coords[0]);
                            airBaseY = Int32.Parse(coords[1]);
                        }
                        continue;
                }

                file.add(flight, key, value);
            }

            //bomber flights are in sets of 3.
            //if less than three, just add them to flight0 and continue
            if (numBombers <= 3)
                file.set(flight, "Flight0", flightValueString(numBombers));
            else
            {
                //if there are more than three, add the first three to flight0
                int flightNum = 0;
                file.set(flight, "Flight" + flightNum, flightValueString(3));
                numBombers -= 3;
                flightNum++;

                //if there are still more than three, add flights of three until there are less than three remaining
                for (int i = 0; i < numBombers / 3; i++)
                {
                    file.set(flight, "Flight" + flightNum, flightValueString(3));
                    numBombers -= 3;
                    flightNum++;
                }

                //if there are still one or two bombers to be added, add them to the next flight
                if (numBombers > 0)
                    file.set(flight, "Flight" + flightNum, flightValueString(numBombers));
            }

            setAirspawnWaypoint(file, flight, airBaseX, airBaseY);

            int xPos, yPos;
            int altitude = rand.Next(2000, 6001);

            if (altitude > 3500)
                setSmallAiPatrol(file, flight, airBaseX, airBaseY, altitude, 1);

            getRandomLandPoint(enemy, out xPos, out yPos);
            setLevelBombWaypoint(file, flight, xPos, yPos, altitude);

            setLandingWaypoint(file, flight, airBaseX, airBaseY, altitude);

            ageFlight(file, flight, rand.Next(1, 76));

            return flight;
        }

        /// <summary>
        /// Creates a random flight of level bombers that will bomb a random point of land on the opposing army's side of the front.
        /// If playerEscort is true, the bombers will circle the playerString's airbase instead of their own.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="army">The army that the bombers will fly for.</param>
        /// <param name="numBombers">The number of bombers.</param>
        /// <param name="mission">The MissionInfo object that the relevant information will be added to.</param>
        /// <param name="playerEscort">Whether or not the playerString will escort the bombers. It does not add the escort waypoints.</param>
        /// <returns></returns>
        private string createRandomBomberFlight(ISectionFile file, int army, int numBombers, MissionInfo mission, bool playerEscort)
        {
            int airBaseX = 0;
            int airBaseY = 0;
            int enemy;

            Random rand = new Random();

            if (numBombers > 10 || numBombers <= 0)
                numBombers = rand.Next(1, 11);

            ISectionFile aircraftFile;

            if (army == 1)
            {
                aircraftFile = redAircraft;
                enemy = 2;
            }
            else
            {
                aircraftFile = blueAircraft;
                enemy = 1;
            }

            string airGroup = chooseRandomFlight(aircraftFile, "Bombers");
            string flight = airGroup + "." + currentFlightNum.ToString("00");
            currentFlightNum += 1;

            file.add("AirGroups", flight, "");

            for (int i = 0; i < aircraftFile.lines(airGroup); i++)
            {
                string key, value;
                aircraftFile.get(airGroup, i, out key, out value);

                switch (key)
                {
                    case "Skill":
                        value = randomSkill();
                        break;
                    case "Airbase":
                        if (value.Equals("Random"))
                            getRandomAirbase(army, out airBaseX, out airBaseY);

                        else
                        {
                            string[] coords = value.Split(' ');
                            airBaseX = Int32.Parse(coords[0]);
                            airBaseY = Int32.Parse(coords[1]);
                        }
                        continue;
                }

                file.add(flight, key, value);
            }

            //bomber flights are in sets of 3.
            //if less than three, just add them to flight0 and continue
            if (numBombers <= 3)
                file.set(flight, "Flight0", flightValueString(numBombers));
            else
            {
                //if there are more than three, add the first three to flight0
                int flightNum = 0;
                file.set(flight, "Flight" + flightNum, flightValueString(3));
                numBombers -= 3;
                flightNum++;

                //if there are still more than three, add flights of three until there are less than three remaining
                for (int i = 0; i < numBombers / 3; i++)
                {
                    file.set(flight, "Flight" + flightNum, flightValueString(3));
                    numBombers -= 3;
                    flightNum++;
                }

                //if there are still one or two bombers to be added, add them to the next flight
                if (numBombers > 0)
                    file.set(flight, "Flight" + flightNum, flightValueString(numBombers));
            }

            setAirspawnWaypoint(file, flight, airBaseX, airBaseY);

            mission.altitude = rand.Next(2000, 6001);

            if (playerEscort)
                setSmallAiPatrol(file, flight, PLAYER_AIRBASE_X, PLAYER_AIRBASE_Y, mission.altitude, 1);
            else if (mission.altitude > 3500)
                setSmallAiPatrol(file, flight, airBaseX, airBaseY, mission.altitude, 1);

            getRandomLandPoint(enemy, mission);
            setLevelBombWaypoint(file, flight, mission.xPos, mission.yPos, mission.altitude);

            setLandingWaypoint(file, flight, airBaseX, airBaseY, mission.altitude);

            ageFlight(file, flight, rand.Next(1, 76));
            
            mission.targetType = aircraftFile.get(airGroup, "Class").Split('.')[1];

            return flight;
        }

        /// <summary>
        /// Removes all airgoups from the file.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        private void removeAllFlights(ISectionFile file)
        {
            for (int i = 0; i < file.lines("AirGroups"); i++)
            {
                string group, value;

                file.get("AirGroups", i, out group, out value);

                file.delete("AirGroups", i);
                file.delete(group);
                file.delete(group + "_way");
            }
        }

        /// <summary>
        /// Creates the player's flight and adds it to the mission based on the info and playerAircraft section files
        /// in the campaigns "Files" folder.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        private void createPlayerFlight(ISectionFile file)
        {
            ISectionFile cpInfo = GamePlay.gpLoadSectionFile(PATH + "Files/info.SECTION");
            ISectionFile playerAircraft = GamePlay.gpLoadSectionFile(PATH + "Files/playerAircraft.SECTION");

            string playerString = cpInfo.get("Info", "playerFlight");
            string playerGroup = playerString.Split('.')[0];
            PLAYER_FLIGHT = playerGroup + ".01";

            file.set("MAIN", "player", playerString);
            file.add("AirGroups", PLAYER_FLIGHT, "");

            file.set(PLAYER_FLIGHT, "Class", cpInfo.get("Info", "playerAircraft"));

            for (int i = 0; i < playerAircraft.lines(playerGroup); i++)
            {
                string key, value;
                playerAircraft.get(playerGroup, i, out key, out value);

                file.set(PLAYER_FLIGHT, key, value);
            }

            file.set(PLAYER_FLIGHT, "Skill", player.skill);
        }

        #endregion

        #region waypoints

        private void setJaboWaypoint(ISectionFile file, string flight, int army, MissionInfo mission, string targetType)
        {
            int enemy;
            ISectionFile aircraftFile;
            if (army == 1)
            {
                enemy = 2;
                aircraftFile = blueAircraft;
            }
            else
            {
                enemy = 1;
                aircraftFile = redAircraft;
            }

            getRandomAirbase(mission, enemy);

            setLevelBombWaypoint(file, flight, mission.xPos, mission.yPos, mission.altitude);

            switch (targetType)
            {
                case "Aircraft":
                    mission.targetType = "the airfield";

                    string target = chooseRandomFlight(aircraftFile, "Fighters");
                    string targetFlight = target + "." + currentFlightNum.ToString("00");
                    currentFlightNum += 1;

                    file.add("AirGroups", targetFlight, "");
                    file.set(targetFlight, "Class", aircraftFile.get(target, "Class"));
                    file.set(targetFlight, "flight0", flightValueString(4));
                    file.set(targetFlight, "Skill", randomSkill());
                    file.set(targetFlight, "SetOnPark", 1);
                    file.set(targetFlight, "Idle", 1);
                    setStaticTakeoffWaypoint(file, targetFlight, mission.xPos, mission.yPos);
                    break;
            }
        }

        private void setJaboWaypoint(ISectionFile file, string flight, int army, MissionInfo mission)
        {
            setJaboWaypoint(file, flight, army, mission, "");
        }

        private void getRandomAirbase(MissionInfo mission, int army)
        {
            ISectionFile airbases = GamePlay.gpLoadSectionFile(PATH + "Files/airfields.SECTION");

            string armyString;
            if (army == 1)
                armyString = "UKAirfields";
            else
                armyString = "DEAirfields";

            Random rand = new Random();
            int line = rand.Next(0, airbases.lines(armyString));

            string key, value;
            airbases.get(armyString, line, out key, out value);

            string[] values = airbases.get(key, "Position").Split(' ');

            mission.xPos = Int32.Parse(values[0]);
            mission.yPos = Int32.Parse(values[1]);
            mission.sector = GamePlay.gpSectorName(mission.xPos, mission.yPos);
        }

        private void getRandomAirbase(int army, out int xPos, out int yPos)
        {
            MissionInfo temp = new MissionInfo();

            getRandomAirbase(temp, army);

            xPos = temp.xPos;
            yPos = temp.yPos;
        }

        /// <summary>
        /// Adds escort waypoint(s) to the players flight.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="target">The flight to be escorted. It must already exist in the mission file.</param>
        private void setPlayerEscort(ISectionFile file, string target)
        {
            Random rand = new Random();

            string bomberWay, bomberValue;
            file.get(target + "_Way", 2, out bomberWay, out bomberValue);
            string[] bomberValues = bomberValue.Split(' ');

            int newAltitude = Int32.Parse(bomberValues[2]) + rand.Next(200, 700);
            setEscortWaypoint(file, Int32.Parse(bomberValues[0]), Int32.Parse(bomberValues[1]), PLAYER_FLIGHT, target, newAltitude);
        }

        /// <summary>
        /// Adds a free hunt waypoint for the airgroup at a random point in the "RED_COASTAL_SECTORS" list.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="airGroup">The airgroup to add the waypoint to</param>
        /// <param name="mission">The MissionInfo object to add the relevant info to.</param>
        private void setCoastalFreeHuntWaypoint(ISectionFile file, string airGroup, MissionInfo mission)
        {
            Random rand = new Random();

            while (!RED_COASTAL_SECTORS.Contains(mission.sector))
            {
                mission.xPos = rand.Next(XMINBOUND, XMAXBOUND);
                mission.yPos = rand.Next(YMINBOUND, YMAXBOUND);
                mission.sector = GamePlay.gpSectorName(mission.xPos, mission.yPos);
            }

            mission.altitude = rand.Next(1000, 6001);

            file.add(airGroup + "_Way", AiAirWayPointType.HUNTING.ToString(), mission.xPos + " " + mission.yPos + " " + mission.altitude + " " + 350);
        }

        /// <summary>
        /// Adds an escort waypoint for "airGroup" to escort "target".
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="xPos">The X position of the bomber's first waypoint.</param>
        /// <param name="yPos">The Y position of the bomber's first waypoint.</param>
        /// <param name="airGroup">The airgroup doing the escorting</param>
        /// <param name="target">The airgroup to be escorted</param>
        /// <param name="altitude">The altitude for the escort waypoint</param>
        private void setEscortWaypoint(ISectionFile file, int xPos, int yPos, string airGroup, string target, int altitude)
        {
            //file.add(airGroup + "_Way", AiAirWayPointType.ESCORT.ToString(), xPos + " " + yPos + " " + altitude + " " + 360 + " " + target + " 1");
            //file.add(airGroup + "_Way", AiAirWayPointType.ESCORT.ToString(), xPos + " " + yPos + " " + altitude + " " + 360 + " " + target + " 2");
            //file.add(airGroup + "_Way", AiAirWayPointType.ESCORT.ToString(), xPos + " " + yPos + " " + altitude + " " + 360 + " " + target + " 3");

            int num = 1;
            for (int i = 2; i < file.lines(target + "_Way"); i++)
            {
                string key, value;
                file.get(target + "_Way", i, out key, out value);
                string[] values = value.Split(' ');
                string pos = values[0] + " " + values[1];

                file.add(airGroup + "_Way", AiAirWayPointType.ESCORT.ToString(), pos + " " + altitude + " " + 360 + " " + target + " " + num);
            }
        }

        /// <summary>
        /// Adds a level bomb waypoint to the airgroup.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="airGroup">The airgroup to add the waypoint to.</param>
        /// <param name="xPos">The X coordinate to bomb at.</param>
        /// <param name="yPos">The Y coordinate to bomb at.</param>
        /// <param name="altitude">The altitude to bomb at.</param>
        private void setLevelBombWaypoint(ISectionFile file, string airGroup, int xPos, int yPos, int altitude)
        {
            file.add(airGroup + "_Way", AiAirWayPointType.GATTACK_POINT.ToString(), xPos + " " + yPos + " " + altitude + " " + 305);
        }

        /// <summary>
        /// Creates a random land point on "controllingArmy"'s side of the front and adds the X and Y coordinates to the MissionInfo object.
        /// </summary>
        /// <param name="controllingArmy">The point will be on this army's side of the front.</param>
        /// <param name="mission">The MissionInfo object to add the information to.</param>
        private void getRandomLandPoint(int controllingArmy, MissionInfo mission)
        {
            Random rand = new Random();

            do
            {
                mission.xPos = rand.Next(XMINBOUND, XMAXBOUND);
                mission.yPos = rand.Next(YMINBOUND, YMAXBOUND);
            }
            while (GamePlay.gpFrontArmy(mission.xPos, mission.yPos) != controllingArmy || GamePlay.gpLandType(mission.xPos, mission.yPos) == LandTypes.WATER);

            mission.sector = GamePlay.gpSectorName(mission.xPos, mission.yPos);
        }

        /// <summary>
        /// Creates a random land point on "controllingArmy"'s side of the front.
        /// </summary>
        /// <param name="controllingArmy">The point will be on this army's side of the front.</param>
        /// <param name="xPos">The X coordinate of the point.</param>
        /// <param name="yPos">The Y coordinate of the point.</param>
        private void getRandomLandPoint(int controllingArmy, out int xPos, out int yPos)
        {
            Random rand = new Random();

            do
            {
                xPos = rand.Next(XMINBOUND, XMAXBOUND);
                yPos = rand.Next(YMINBOUND, YMAXBOUND);
            }
            while (GamePlay.gpFrontArmy(xPos, yPos) != controllingArmy || GamePlay.gpLandType(xPos, yPos) == LandTypes.WATER);
        }

        /// <summary>
        /// Adds waypoints to the airgroup that will have it patrolling around a specified point.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="airGroup">The airgroup to add waypoints to.</param>
        /// <param name="xPos">The X coordinate to patrol around.</param>
        /// <param name="yPos">The Y coordinate to patrol around.</param>
        /// <param name="altitude">The altitude to patrol at.</param>
        /// <param name="iterations">The number of "loops" to do around the point.</param>
        private void setAiPatrol(ISectionFile file, string airGroup, int xPos, int yPos, int altitude, int iterations)
        {
            int oneX, oneY, twoX, twoY, threeX, threeY, fourX, fourY;

            Random rand = new Random();

            oneX = xPos + rand.Next(3000, 6000);
            oneY = yPos + rand.Next(3000, 6000);
            twoX = xPos + rand.Next(3000, 6000);
            twoY = yPos - rand.Next(3000, 6000);
            threeX = xPos - rand.Next(3000, 6000);
            threeY = yPos - rand.Next(3000, 6000);
            fourX = xPos - rand.Next(3000, 6000);
            fourY = yPos + rand.Next(3000, 6000);

            for (int i = 0; i < iterations; i++)
            {
                file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), oneX + " " + oneY + " " + altitude + " " + 350);
                file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), twoX + " " + twoY + " " + altitude + " " + 350);
                file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), threeX + " " + threeY + " " + altitude + " " + 350);
                file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), fourX + " " + fourY + " " + altitude + " " + 350);
            }
        }

        /// <summary>
        /// The same as setAiPatrol, only with smaller "loops".
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="airGroup">The airgroup to add waypoints to.</param>
        /// <param name="xPos">The X coordinate to patrol around.</param>
        /// <param name="yPos">The Y coordinate to patrol around.</param>
        /// <param name="altitude">The altitude to patrol at.</param>
        /// <param name="iterations">The number of "loops" to do around the point.</param>
        private void setSmallAiPatrol(ISectionFile file, string airGroup, int xPos, int yPos, int altitude, int iterations)
        {
            int oneX, oneY, twoX, twoY, threeX, threeY, fourX, fourY;

            oneX = xPos + 3000;
            oneY = yPos + 3000;
            twoX = xPos + 3000;
            twoY = yPos - 3000;
            threeX = xPos - 3000;
            threeY = yPos - 3000;
            fourX = xPos - 3000;
            fourY = yPos + 3000;

            for (int i = 0; i < iterations; i++)
            {
                file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), oneX + " " + oneY + " " + altitude + " " + 300);
                file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), twoX + " " + twoY + " " + altitude + " " + 300);
                file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), threeX + " " + threeY + " " + altitude + " " + 300);
                file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), fourX + " " + fourY + " " + altitude + " " + 300);
            }
        }

        /// <summary>
        /// Adds the necessary waypoints to the airgroup to make it takeoff.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="airGroup">The airgroup to add waypoints to.</param>
        /// <param name="x">The X coordinate to takeoff from.</param>
        /// <param name="y">The Y coordinate to takeoff from.</param>
        private void setTakeoffWaypoint(ISectionFile file, string airGroup, int x, int y)
        {
            file.add(airGroup + "_Way", AiAirWayPointType.TAKEOFF.ToString(), x + " " + y + " " + 0 + " " + 0);
            file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), (x + 2000) + " " + y + " " + 500 + " " + 300);
        }

        /// <summary>
        /// Adds the necessary takeoff waypoint to make a group spawn at an airfield but not takeoff.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="airGroup">The airgroup to add waypoints to.</param>
        /// <param name="x">The X coordinate to takeoff from.</param>
        /// <param name="y">The Y coordinate to takeoff from.</param>
        private void setStaticTakeoffWaypoint(ISectionFile file, string airGroup, int x, int y)
        {
            file.add(airGroup + "_Way", AiAirWayPointType.TAKEOFF.ToString(), x + " " + y + " " + 0 + " " + 0);
        }

        /// <summary>
        /// Adds the necessary waypoints to the airgroup to make it airspawn.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="airGroup">The airgroup to add waypoints to.</param>
        /// <param name="x">The X coordinate to airspawn at.</param>
        /// <param name="y">The Y coordinate to airspawn at.</param>
        private void setAirspawnWaypoint(ISectionFile file, string airGroup, int x, int y)
        {
            int add = currentFlightNum * 500;

            file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), x + " " + (y + add) + " " + 500 + " " + 300);
            file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), (x + 2000) + " " + (y + add) + " " + 500 + " " + 300);
        }
        
        /// <summary>
        /// Adds the necessary waypoints to the airgroup to make it airspawn.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="airGroup">The airgroup to add waypoints to.</param>
        /// <param name="x">The X coordinate to airspawn at.</param>
        /// <param name="y">The Y coordinate to airspawn at.</param>
        /// <param name="altitude">The altitude to airspawn at.</param>
        private void setAirspawnWaypoint(ISectionFile file, string airGroup, int x, int y, int altitude)
        {
            int add = currentFlightNum * 500;

            file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), x + " " + (y + add) + " " + altitude + " " + 300);
            file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), (x + 2000) + " " + (y + add) + " " + altitude + " " + 300);
        }

        /// <summary>
        /// Adds the necessary waypoints to the airgroup to make it land.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        /// <param name="airGroup">The airgroup to add waypoints to.</param>
        /// <param name="x">The X coordinate to land at.</param>
        /// <param name="y">The Y coordinate to land at.</param>
        /// <param name="altitude">The altitude of the previous waypoint.</param>
        private void setLandingWaypoint(ISectionFile file, string airGroup, int x, int y, int altitude)
        {
            file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), (x + 4000) + " " + y + " " + altitude + " " + 330);
            file.add(airGroup + "_Way", AiAirWayPointType.NORMFLY.ToString(), (x + 2000) + " " + y + " " + 500 + " " + 300);
            file.add(airGroup + "_Way", AiAirWayPointType.LANDING.ToString(), x + " " + y + " " + 0 + " " + 0);
        }

        #endregion

        #region misc

        /// <summary>
        /// Sets the name of the folder that the campaign resides in.
        /// </summary>
        /// <param name="folder">The folder that the campaign resides in.</param>
        public void setCampaignFolder(string folder)
        {
            USER_PATH = USER_FOLDER + folder + "/";
            PATH = CAMPAIGN_FOLDER + folder + "/";
            
        }

        /// <summary>
        /// Performs the necessary steps before the mission can begin.
        /// </summary>
        private void setup()
        {
            playerDead = false;

            blueAircraft = GamePlay.gpLoadSectionFile(PATH + "Files/blueAircraft.SECTION");
            redAircraft = GamePlay.gpLoadSectionFile(PATH + "Files/redAircraft.SECTION");

            campaignInfo = GamePlay.gpLoadSectionFile(PATH + "Files/info.SECTION");
            try
            {
                playerState = GamePlay.gpLoadSectionFile(USER_PATH + "playerState.ini");
            }
            catch (Exception e)
            {
                playerState = GamePlay.gpCreateSectionFile();
            }
            if (!playerState.exist("PlayerInfo"))
                firstMission = true;

            string[] airbase = campaignInfo.get("Info", "Airbase").Split(' ');
            PLAYER_AIRBASE_X = Int32.Parse(airbase[0]);
            PLAYER_AIRBASE_Y = Int32.Parse(airbase[1]);

            parseBattleAreaAndCoastalSectors();

            player = new PlayerInfo(playerState, GamePlay.gpPlayer().Name());

            if (firstMission)
                player.reset(campaignInfo);

            if(!firstMission)
                player.addSortie();
        }

        /// <summary>
        /// Parses the battle area and coastal sectors out of "Files/base.mis".
        /// </summary>
        private void parseBattleAreaAndCoastalSectors()
        {
            ISectionFile baseFile = GamePlay.gpLoadSectionFile(PATH + "Files/base.mis");

            string value = baseFile.get("MAIN", "MissionBounds");

            string[] values = value.Split(' ');

            XMINBOUND = Int32.Parse(values[0]);
            YMINBOUND = Int32.Parse(values[1]);

            XMAXBOUND = Int32.Parse(values[2]);
            YMAXBOUND = Int32.Parse(values[3]);

            value = baseFile.get("MAIN", "RedCoastalSectors");
            values = value.Split(' ');

            foreach (string s in values)
                RED_COASTAL_SECTORS.Add(s);
        }

        /// <summary>
        /// Randomizes the weather. This includes time, "weather index", breeze and thermal activity, and wind direction and power.
        /// </summary>
        /// <param name="file">The mission file to be modified.</param>
        private void randomizeWeather(ISectionFile file)
        {
            Random rand = new Random();
            file.set("Main", "TIME", rand.Next(4, 19));
            file.set("Main", "WeatherIndex", rand.Next(0, 4));
            file.set("Main", "BreezeActivity", rand.Next(0, 4));
            file.set("Main", "ThermalActivity", rand.Next(0, 4));
            file.set("Main", "CloudsHeight", rand.Next(500, 2001));

            string power = "";

            for (int i = 0; i < 2; i++)
            {
                double w = rand.NextDouble();

                int neg = rand.Next(0, 2);
                if (neg == 0)
                    w = w * (-1);

                power += w.ToString("0.000", new System.Globalization.CultureInfo("en-US"));
                power += " ";
            }

            power += "0.000";
            file.set("GlobalWind_0", "Power", power);

            file.set("GlobalWind_0", "GustPower", rand.Next(0, 4));
            file.set("GlobalWind_0", "GustAngle", rand.Next(-45, 45));
        }

        /// <summary>
        /// Performs the necessary actions to signal the end of the current campaign.
        /// </summary>
        private void endCampaign()
        {
            ISectionFile state = GamePlay.gpLoadSectionFile(USER_PATH + "state.ini");
            state.add("Complete", "Complete", "Complete");
            state.save(USER_PATH + "state.ini");
        }

        /// <summary>
        /// Reads the settings from the user-modifiable conf.ini file.
        /// </summary>
        private void updateSettings()
        {
            ISectionFile confFile = GamePlay.gpLoadSectionFile(PATH + "conf.ini");

            maxAircraft = Int32.Parse(confFile.get("Config", "maxAircraft"));
            minAircraft = Int32.Parse(confFile.get("Config", "minAircraft"));
            maxAiSkill = Int32.Parse(confFile.get("Config", "maxAiSkill"));
            minAiSkill = Int32.Parse(confFile.get("Config", "minAiSkill"));
        }

        /// <summary>
        /// Adds the "Stationary" and "Buildings" sections of one file to another.
        /// </summary>
        /// <param name="file">The mission file to add the sections to.</param>
        /// <param name="sourceFile">The file to get the sections from.</param>
        private void addStatic(ISectionFile file, string sourceFile)
        {
            ISectionFile staticObjects = GamePlay.gpLoadSectionFile(PATH + sourceFile);

            for (int i = 0; i < staticObjects.lines("Stationary"); i++)
            {
                string key, value;
                staticObjects.get("Stationary", i, out key, out value);

                file.add("Stationary", key, value);
            }

            for (int i = 0; i < staticObjects.lines("Buildings"); i++)
            {
                string key, value;
                staticObjects.get("Buildings", i, out key, out value);

                file.add("Buildings", key, value);
            }
        }

        /// <summary>
        /// Ages the specified flight by the specified amount. When age reaches 100, it resets to 0.
        /// </summary>
        /// <param name="file">The mission file to modify.</param>
        /// <param name="amount">The amount to increase the age by.</param>
        private void agePlayerFlight(ISectionFile file, int amount)
        {
            int currentAge = player.getAge();

            currentAge += amount;

            if (currentAge < 100)
            {
                file.set(PLAYER_FLIGHT, "Aging", currentAge);
                file.set(PLAYER_FLIGHT, "Aging0", currentAge);
            }
            else
            {
                currentAge = 0;
                file.set(PLAYER_FLIGHT, "Aging", currentAge);
                file.set(PLAYER_FLIGHT, "Aging0", currentAge);
            }

            player.setAge(currentAge);
        }

        /// <summary>
        /// Sets the age of the flight to the specified amount.
        /// </summary>
        /// <param name="file">The file to be modified</param>
        /// <param name="flight">The flight to age.</param>
        /// <param name="age">The value to set the age to.</param>
        private void ageFlight(ISectionFile file, string flight, int age)
        {
            file.set(flight, "Aging", age);
        }

        #endregion
    }

    #region classes

    /// <summary>
    /// Keeps track of information related to the playerString, including name, current date in the campaign, number of kills, etc.
    /// </summary>
    internal class PlayerInfo
    {
        private DateTime date = new DateTime(1940, 7, 15);

        private ISectionFile playerState;

        private int victories = 0;
        private int sorties = 0;
        private int timesShotDown = 0;
        private int aircraftAge = 0;

        public string name { get; private set; }
        public string skill { get; set; }

        public List<Victim> newVictims { get; private set; }

        public PlayerInfo(ISectionFile stateFile, string name)
        {
            playerState = stateFile;
            checkInfoExists(playerState);

            victories = Int32.Parse(playerState.get("PlayerInfo", "victories"));
            sorties = Int32.Parse(playerState.get("PlayerInfo", "sorties"));
            timesShotDown = Int32.Parse(playerState.get("PlayerInfo", "timesShotDown"));
            aircraftAge = Int32.Parse(playerState.get("PlayerInfo", "Aging"));
            skill = playerState.get("PlayerInfo", "Skill");

            date = DateTime.Parse(playerState.get("PlayerInfo", "Date"));
            newVictims = new List<Victim>();

            this.name = name;
        }

        public void addSortie()
        {
            sorties++;
        }
        public void addVictory(AiAircraft victim)
        {
            victories++;

            if (victim == null)
                return;
            
            Victim v = new Victim();
            
            v.type = victim.InternalTypeName().Split('.')[1];
            v.date = date;

            newVictims.Add(v);
        }
        public void addShotDown()
        {
            timesShotDown++;
        }
        public void addDays(int days)
        {
            date = date.AddDays(days);
        }
        public void setAge(int age)
        {
            aircraftAge = age;
        }

        public int getSorties()
        {
            return sorties;
        }
        public int getVictories()
        {
            return victories;
        }
        public int getShotDown()
        {
            return timesShotDown;
        }
        public int getAge()
        {
            return aircraftAge;
        }
        public DateTime getDate()
        {
            return date;
        }

        public string getListofVictories()
        {
            StringBuilder s = new StringBuilder();

            for (int i = 0; i <= playerState.lines("Victories"); i++)
            {
                s.Append(playerState.get("Victories", i.ToString()));
                s.Append("\r\n");
            }

            return s.ToString();
        }

        public void save(ISectionFile stateFile, string filename)
        {
            checkInfoExists(stateFile);

            stateFile.set("PlayerInfo", "victories", victories);
            stateFile.set("PlayerInfo", "sorties", sorties);
            stateFile.set("PlayerInfo", "timesShotDown", timesShotDown);
            stateFile.set("PlayerInfo", "Aging", aircraftAge);
            stateFile.set("PlayerInfo", "Skill", "0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5");
            stateFile.set("PlayerInfo", "Date", date.ToString("D"));

            int i = stateFile.lines("Victories") + 1;

            foreach (Victim v in newVictims)
            {
                stateFile.set("Victories", i.ToString(), v.ToString());
                i++;
            }

            stateFile.save(filename);
        }

        public void reset(ISectionFile cpInfo)
        {
            victories = 0;
            sorties = 0;
            timesShotDown = 0;
            aircraftAge = 0;
            date = DateTime.Parse(cpInfo.get("Info", "startDate"));

            playerState.delete("Victories");
            newVictims.Clear();
        }

        private void checkInfoExists(ISectionFile stateFile)
        {
            if (!stateFile.exist("PlayerInfo"))
            {
                stateFile.add("PlayerInfo", "victories", "0");
                stateFile.add("PlayerInfo", "sorties", "0");
                stateFile.add("PlayerInfo", "timesShotDown", "0");
                stateFile.add("PlayerInfo", "Aging", "0");
                stateFile.add("PlayerInfo", "Skill", "0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5");
                stateFile.add("PlayerInfo", "Date", date.ToString("D"));
            }
            if (!stateFile.exist("Victories"))
            {
                stateFile.add("Victories", "", "");
            }
        }
    }

    /// <summary>
    /// Represents an aircraft that the playerString has shot down.
    /// </summary>
    internal class Victim
    {
        public string type { get; set; }
        public DateTime date { get; set; }

        public Victim()
        {
            type = "";
        }

        public override string ToString()
        {
            string s = date.ToString("d") + " " + type;

            return s;
        }
    }

    #endregion

    #region interfaces

    public interface ICampaign
    {
        bool? battleSuccess { get; set; }
    }
    #endregion
}